/*
 * Room.cpp
 *
 *  Created on: 30.10.2013
 *      Author: ulgish
 */

#include <lab3/Room.h>
#include <SyncWriter.h>
#include <string>
#include <sstream>
#include <unistd.h>
using std::stringstream;
namespace DT {

#define WAITING true
#define NO_WAITING false

Room::Room(const int& maxCount) {
	stringstream ss;
	this->maxCountOfThinkers = maxCount;
	this->currentCountOfThinkers = 0;
	this->currentCountOfWaitingThinkers = 0;
	this->forksUsed = new bool[this->maxCountOfThinkers];
	this->idOfThinkers = new int[this->maxCountOfThinkers];
	this->forks = new pthread_mutex_t[this->maxCountOfThinkers];
	this->closed = false;
	pthread_mutex_init(&mutexOfCount, NULL);
	for (int i = 0; i < this->maxCountOfThinkers; i++){
		pthread_mutex_init(this->forks + i, NULL);

		forksUsed[i] = false;
		idOfThinkers[i] = -1;
	}

}
void Room::addCount(bool isWaiting){
	pthread_mutex_lock(&mutexOfCount);
	if (!isWaiting){
		currentCountOfThinkers++;
	}else{
		currentCountOfWaitingThinkers++;
	}

	pthread_mutex_unlock(&mutexOfCount);

}
void Room::subCount(bool isWaiting){
	pthread_mutex_lock(&mutexOfCount);
	if (!isWaiting){
		currentCountOfThinkers--;
	}else{
		currentCountOfWaitingThinkers--;
	}

	pthread_mutex_unlock(&mutexOfCount);

}

int Room::getNumberOfNextFork(int i){
	return ((++i)%maxCountOfThinkers);
}

void Room::feed(const int& timeOfFeeding, const Thinker* thinker)
{
	addCount(NO_WAITING);
	bool iHaveEaten = false;
	while (!iHaveEaten){
		for (int i = 0; i < maxCountOfThinkers; i++){
			if (!forksUsed[i]){
				pthread_mutex_lock(forks + i);
				forksUsed[i] = true;
				idOfThinkers[i] = thinker->getId();
				usleep(10*1000);
				addCount(WAITING);
				if (closed){
					iHaveEaten = true;
					subCount(WAITING);
					forksUsed[i] = false;
					idOfThinkers[i] = -1;
					pthread_mutex_unlock(forks + i);

					break;
				}
				pthread_mutex_lock(forks + getNumberOfNextFork(i));
				forksUsed[getNumberOfNextFork(i)] = true;
				idOfThinkers[getNumberOfNextFork(i)] = thinker->getId();
				sleep(timeOfFeeding);
				iHaveEaten = true;
				forksUsed[getNumberOfNextFork(i)] = false;
				idOfThinkers[getNumberOfNextFork(i)] = -1;
				pthread_mutex_unlock(forks + getNumberOfNextFork(i));
				subCount(WAITING);
				forksUsed[i] = false;
				idOfThinkers[i] = -1;
				pthread_mutex_unlock(forks + i);
				break;
			}
		}//for
		if (!iHaveEaten){
			usleep(10*1000);
			if (closed){
				iHaveEaten = true;
				break;
			}
		}
	}//while !iHaveEaten
	subCount(NO_WAITING);
}

void Room::print(){
	stringstream ss;
	ss << "Max count of Thinkers:\t" << maxCountOfThinkers << "\n";
	ss << "Current count of Thinkers:\t" << currentCountOfThinkers << "\n";
	ss << "Current count of Waiting Thinkers:\t" << currentCountOfWaitingThinkers << "\n";
	for (int i = 0; i < maxCountOfThinkers; i++){
		if (forksUsed[i]){
			ss << "fork[" << i << "] used (id:" << idOfThinkers[i] << ")\n";
		}else{
			ss << "fork[" << i << "] not used (id:" << idOfThinkers[i] << ")\n";
		}
	}
	ss << "\n";
	writer << ss.str();
	return ;
}

Room::~Room() {
	for (int i = 0; i < this->maxCountOfThinkers; i++){
		pthread_mutex_destroy(this->forks + i);
	}
	delete []this->forks;
	delete []this->forksUsed;

}

}
